# -*- coding: utf-8 -*-
#
# Copyright © 2009 Benedikt Eger
#
# This file is part of top-news-buzz.
#
# top-news-buzz is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# top-news-buzz is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with top-news-buzz.  If not, see <http://www.gnu.org/licenses/>.

import logging
import re

from datetime import datetime, timedelta

from google.appengine.ext import db
from google.appengine.api import memcache

from topnewsbuzz.config import Config
from topnewsbuzz.utils import DateHelper

class NewsArticle(db.Model):
    title = db.StringProperty(required = True)
    url = db.LinkProperty(required = True)
    # TODO: make the id a required property again if the data in the deployed version allows it
    id = db.IntegerProperty()
    content = db.TextProperty()
    score = db.FloatProperty(default = 0.0)
    score_boost = db.FloatProperty(default = 1.0)
    score_date = db.DateTimeProperty()
    publish_date = db.DateTimeProperty(auto_now_add = True)
    publish_year = db.IntegerProperty()
    publish_month = db.IntegerProperty()
    publish_day = db.IntegerProperty()
    publish_isoweek = db.IntegerProperty()
    publish_isoyear = db.IntegerProperty()

    def domain(self):
        match = re.match("http?://([^/]*)/.*", self.url)
        if match is not None:
            return match.group(1)

class NewsManager:

    DATASTORE_RETRIEVAL_LIMIT = 1000

    MEMCACHE_N_DAYS_KEY = 'memcache_n_days'

    @staticmethod
    def get_top_news(date, page):
        offset = (page - 1) * Config.articles_to_display()
        if(date.date_type == DateHelper.DATE_TYPE_LAST_N_DAYS):
            memcache_key = '%s_%i' % (NewsManager.MEMCACHE_N_DAYS_KEY, page)
            news_list = memcache.get(memcache_key)
            if news_list is None:
                date_n_days_ago = datetime.now() - timedelta(days = Config.display_last_n_days())
                query = db.GqlQuery('SELECT * FROM NewsArticle WHERE publish_date > :date_n_days_ago', date_n_days_ago = date_n_days_ago)
                news_list = query.fetch(NewsManager.DATASTORE_RETRIEVAL_LIMIT)
                news_list.sort(lambda x, y: int(y.score - x.score))
                if len(news_list) == NewsManager.DATASTORE_RETRIEVAL_LIMIT:
                    logging.warn('Number of news from the last 24 hours is at least 1000. Results may not be accurate.')
                news_list = news_list[offset:Config.articles_to_display() + offset]
                memcache.set(memcache_key, news_list)
        elif(date.date_type == DateHelper.DATE_TYPE_YEAR):
            query = db.GqlQuery('SELECT * FROM NewsArticle WHERE publish_year = :year ORDER BY score DESC', year = date.selected_year)
            news_list = query.fetch(Config.articles_to_display(), offset)
        elif(date.date_type == DateHelper.DATE_TYPE_MONTH):
            query = db.GqlQuery('SELECT * FROM NewsArticle WHERE publish_year = :year AND publish_month = :month ORDER BY score DESC', year = date.selected_year, month = date.selected_month)
            news_list = query.fetch(Config.articles_to_display(), offset)
        elif(date.date_type == DateHelper.DATE_TYPE_WEEK):
            query = db.GqlQuery('SELECT * FROM NewsArticle WHERE publish_isoyear = :year AND publish_isoweek = :week ORDER BY score DESC', year = date.selected_year, week = date.selected_week)
            news_list = query.fetch(Config.articles_to_display(), offset)
        else:
            query = db.GqlQuery('SELECT * FROM NewsArticle WHERE publish_year = :year AND publish_month = :month AND publish_day = :day ORDER BY score DESC', year = date.selected_year, month = date.selected_month, day = date.selected_day)
            news_list = query.fetch(Config.articles_to_display(), offset)

        return news_list

    @staticmethod
    def get_news_by_id(id):
        query = db.GqlQuery('SELECT * FROM NewsArticle WHERE id= :id', id = id)
        result = query.fetch(1)
        if len(result) > 0:
            return result[0]

    @staticmethod
    def invalidate_memcache():
        memcache.flush_all()
